package org.example.executor;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author Yyming
 * @version 10.0
 * Created by Yyming on 2020/12/3
 */
public class MyExecutorCopy {
    public static void main(String[] args) {
        ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newCachedThreadPool();
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(111);
            }
        });
    }
    private volatile int corePollSize;
    private volatile int maximumPoolSize;
    private volatile int keepAliveTime;
    private volatile BlockingQueue<Runnable> task;
    private volatile ThreadFactory threadFactory;
    private volatile RejectedExecutionHandler handler;
    private volatile TimeUnit unit;

    private int theadNum = 0;
    private Set<Worker> workers = new HashSet<>();

    public MyExecutorCopy(int corePollSize, int maximumPoolSize, int keepAliveTime, BlockingQueue<Runnable> task, ThreadFactory threadFactory, RejectedExecutionHandler handler, TimeUnit unit) {
        this.corePollSize = corePollSize;
        this.maximumPoolSize = maximumPoolSize;
        this.keepAliveTime = keepAliveTime;
        this.task = task;
        this.threadFactory = threadFactory;
        this.handler = handler;
        this.unit = unit;
    }

    public void execute(Runnable task) {
        if (theadNum < corePollSize) {
            addWorker(task);
            return;
        } else if (this.task.offer(task)){

        } else if (theadNum < maximumPoolSize) {
            addWorker(task);
            return;
        }
        handler.rejectedExecution(task, null);
    }

    private void addWorker(Runnable task) {
        Worker worker = new Worker(task);
        workers.add(worker);
        Thread thread = worker.thread;
        thread.start();
        theadNum++;
    }

    private class Worker implements Runnable{
        Runnable task;
        Thread thread;


        public Worker(Runnable task) {
            this.task = task;
            this.thread = threadFactory.newThread(this);
        }

        @Override
        public void run() {
            try {
                doWroker(this);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void doWroker(Worker worker) throws InterruptedException {
        Runnable task = worker.task;
        while (task != null || (task != getTask())) {
            task.run();
            task = null;
        }

        theadNum--;
    }

    private Runnable getTask() throws InterruptedException {
       if (theadNum < corePollSize) {
           return task.take();
       } else {
           return task.poll(keepAliveTime, unit);
       }
    }


}
